package cn.lg.soar.database.datascope;

import cn.lg.soar.core.annotations.DataScope;
import org.springframework.util.ConcurrentReferenceHashMap;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author luguoxiang 469599794@qq.com
 * @Date: 2024/3/1 21:59
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public final class DataScopeHolder {

    private static final ThreadLocal<DataScope> RESOURCE_CODE = new ThreadLocal<>();
    private static final ThreadLocal<Integer> IGNORE = ThreadLocal.withInitial(() -> 0);

    private static final List<String> IGNORE_CLASS = new ArrayList<>();
    private static final Map<String, Byte> IGNORE_ID = new ConcurrentReferenceHashMap<>();

    /**
     * 设置资源编码
     * @param value
     */
    static void setResourceCode(DataScope value) {
        RESOURCE_CODE.set(value);
    }

    /**
     * 获取当前资源编码
     * @return
     */
    public static DataScope getResourceCode() {
        return RESOURCE_CODE.get();
    }

    /**
     * 删除资源编码
     */
    static void delResourceCode() {
        RESOURCE_CODE.remove();
    }

    /**
     * 判断是否忽略
     * @return
     */
    public static boolean isIgnore() {
        return IGNORE.get() > 0;
    }

    /**
     * 判断是否忽略
     * @param mappedStatementId
     * @return
     */
    public static boolean isIgnore(String mappedStatementId) {
        if (IGNORE.get() > 0) {
            return true;
        }
        // 判断是否忽略
        if (IGNORE_ID.containsKey(mappedStatementId)) {
            return true;
        }
        // 判断类是否忽略
        for (String s : IGNORE_CLASS) {
            if (mappedStatementId.startsWith(s)) {
                addIgnore(mappedStatementId);
                return true;
            }
        }
        return false;
    }

    /**
     * 添加忽略（从调用该方法的地方开始到 delIgnore 结束的所有数据库操作都将忽略数据权限控制）
     * 注意：必须和 delIgnore 成对使用，否则有内存泄漏风险
     */
    static void addIgnore() {
        IGNORE.set(IGNORE.get() + 1);
    }

    /**
     * 删除忽略
     */
    static void delIgnore() {
        int i = IGNORE.get() - 1;
        if (Objects.equals(i, 0)) {
            IGNORE.remove();
        } else {
            IGNORE.set(i);
        }
    }

    /**
     * 添加忽略（忽略该类下所有方法的数据权限控制）
     * @param clazz 类
     */
    public static void addIgnore(Class<?> clazz) {
        IGNORE_CLASS.add(clazz.getName());
    }

    /**
     * 添加忽略（忽略某个mapper方法的数据权限控制）
     * @param mappedStatementId
     */
    public static void addIgnore(String mappedStatementId) {
        IGNORE_ID.put(mappedStatementId, (byte) 1);
    }

}
